package org.gruposp2p.dnie.server.rest;

import com.sun.jersey.api.representation.Form;
import java.io.File;
import java.io.FileNotFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.gruposp2p.dnie.crypto.JKSKeyStore;
import org.gruposp2p.dnie.crypto.SignatureValidator;
import org.gruposp2p.dnie.crypto.Signer;
import org.gruposp2p.dnie.model.DNIeDocumentToSign;
import org.gruposp2p.dnie.model.DNIePrincipal;
import org.gruposp2p.dnie.model.DNIeSignedDocument;
import org.gruposp2p.dnie.model.DNIeUser;
import org.gruposp2p.dnie.service.DNIeDocumentToSignDAO;
import org.gruposp2p.dnie.service.DNIeSignedDocumentDAO;
import org.gruposp2p.dnie.service.DNIeUserDAO;
import org.gruposp2p.dnie.utils.DateUtils;
import org.gruposp2p.dnie.utils.XmlUtils;
import org.gruposp2p.dnie.xml.jaxb.DocumentMarshaller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;
import java.io.InputStream;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.List;
import javax.security.auth.x500.X500Principal;
import javax.ws.rs.Consumes;
import org.gruposp2p.dnie.model.SignedDocument;
import org.gruposp2p.dnie.xml.jaxb.DocumentUnMarshaller;

/**
 *
 * @author jj
 */
@Path(value = "/dnieSignedDocuments")
@Component
@Scope("request")
public class DnieSignedDocumentsResource {

    private static Logger logger =
            LoggerFactory.getLogger(DnieSignedDocumentsResource.class);

    @Autowired
    private DNIeSignedDocumentDAO signedDocumentDao;
    @Autowired
    private DNIeUserDAO userDao;
    @Autowired
    private DNIeDocumentToSignDAO documentToSignDAO;    
    
    @Context HttpServletRequest request;

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Response post (Form formData) {
        try {
            String xmlStrSignedDocument = formData.getFirst("xmlStrSignedDocument");
            return validateSignature(xmlStrSignedDocument);
    	} catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            throw new WebApplicationException(Response.Status.BAD_REQUEST);
    	}
    }

    private Response validateSignature (String xmlStrSignedDocument) throws Exception {
    	Response result = null;
    	boolean xmlValidationResult = false;
        SignatureValidator validator = new SignatureValidator ();
        xmlValidationResult = validator.validateSignature(
            XmlUtils.getDocumentFromString(xmlStrSignedDocument, true), false);

        if (!xmlValidationResult)
            Response.status(Status.BAD_REQUEST).build();

        X509Certificate cert = validator.getCertificate();
        X500Principal principal = cert.getSubjectX500Principal();
        DNIePrincipal dniePrincipal = 
        	new DNIePrincipal(principal.getName(X500Principal.RFC1779));
        DNIeUser user = userDao.findByNif(dniePrincipal.SERIALNUMBER);
        if (user == null) {
            user = new DNIeUser();
            user.setNif(dniePrincipal.SERIALNUMBER);
            user.setName(dniePrincipal.CN);
            userDao.save(user);
        }
        SignedDocument signedDocument = (SignedDocument) DocumentUnMarshaller
                .unMarshallObject(xmlStrSignedDocument);
        DNIeDocumentToSign documentToSign = documentToSignDAO.findById(
            signedDocument.signatureDataWrapper.dnieSignedDocument.getDnieDocumentToSignId().getId());
        DNIeSignedDocument savedSignedDocument = 
        	signedDocumentDao.findByUserAndDocumentToSign(user, documentToSign);
        if (savedSignedDocument == null) {
            DNIeSignedDocument dnieSignedDocument = new DNIeSignedDocument();
            dnieSignedDocument.setDnieDocumentToSignId(documentToSign);
            dnieSignedDocument.setXmlDsigData(xmlStrSignedDocument);
            dnieSignedDocument.setDnieUserId(user);
            dnieSignedDocument.setDate(DateUtils.getTodayDate());
            dnieSignedDocument = signedDocumentDao.save(dnieSignedDocument);
            String receipt = signReceipt(dnieSignedDocument);
            result = Response.ok().entity(receipt).build();
        } else if (savedSignedDocument != null){
            String receipt = signReceipt(savedSignedDocument);
            result = Response.status(Status.PRECONDITION_FAILED)
                .entity(receipt).build();
        }
        return result;
    }

    private String signReceipt (DNIeSignedDocument savedSignedDocument) throws FileNotFoundException {
        //TODO This is only for rapid prototyping !!!!
        String password = "gruposp2p";
        //InputStream is = this.getClass().getClassLoader().getResourceAsStream(
        //		"serverKeystore.jks");
        URL url = this.getClass().getClassLoader().getResource("serverKeystore.jks");
        logger.debug("url.getFile(): " + url.getFile());
        JKSKeyStore keyStore = new JKSKeyStore(password, url.getFile(), "jettykey");
        String xmlSignedDocument = null;
        try {
            xmlSignedDocument = Signer.createEnvelopingSignature(
                DocumentMarshaller.marshallObjectToDocument(savedSignedDocument),
                keyStore.getCertificate(), keyStore.getPrivateKey());
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
        return xmlSignedDocument;
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Response get(
            @QueryParam("documentToSignId") Integer documentToSignId,
            @QueryParam("firstResult") @DefaultValue("0") int firstResult,
            @QueryParam("numberResults") @DefaultValue("15") int numberResults) {
        List<DNIeSignedDocument> docs = null;
        DNIeDocumentToSign  documentToSign = 
        	documentToSignDAO.findById(documentToSignId);
        if (documentToSign == null)  
        	Response.status(Status.NOT_FOUND).build();
        try {
            docs = signedDocumentDao.findList(
            		documentToSign, firstResult, numberResults);
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            throw new WebApplicationException(Response.Status.BAD_REQUEST);
    	}
        GenericEntity<Collection<DNIeSignedDocument>> ge =
                new GenericEntity<Collection<DNIeSignedDocument>>(docs) {};
        return Response.ok().entity(ge).build();
    }
}